package com.choosefine.base.shixiaobao.common.utils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.choosefine.base.shixiaobao.common.def.ResultCode;
import com.choosefine.base.shixiaobao.common.exception.BusinessException;

/**
 * Comments：链表校验
 * Author：juchengyang
 * Create Date：2017-03-27
 * Modified By：
 * Modified Date：
 * Why & What is modified：
 * Version：v1.0
 */
public class LinkedListCheck {

    /** 
     * @Description：链表排序算法（通用）
     * @Author：juchengyang
     * @Create 2017-03-27
     */
    public static List listOrder(List list) throws Exception {
        if (list.isEmpty()) {
            return new ArrayList();
        }
        checkList(list);
        int size = list.size();
        Method methodGetId = list.get(0).getClass().getDeclaredMethod("getId");
        Method methodGetSortNum = list.get(0).getClass().getDeclaredMethod("getSortNum");
        List returnList = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            if (i == 0) {
                for (int j = 0; j < size; j++) {
                    if (methodGetSortNum.invoke(list.get(j)).equals(0)) {
                        returnList.add(list.get(j));
                        break;
                    }
                }
            } else {
                for (int j = 0; j < size; j++) {
                    if (methodGetId.invoke(returnList.get(returnList.size() - 1)).equals(methodGetSortNum.invoke(list.get(j)))) {
                        returnList.add(list.get(j));
                        break;
                    }
                }
            }
        }
        if (size != returnList.size()) {
            throw new BusinessException(ResultCode.FAILED, "数据不完整（存在小闭环），没有数据指向 Id = " + methodGetId.invoke(returnList.get(returnList.size() - 1)));
        }
        for (int i = 0; i < returnList.size() / 2; i++) {
            Object temp = returnList.get(i);
            returnList.set(i, returnList.get(returnList.size() - i - 1));
            returnList.set(returnList.size() - i - 1, temp);
        }
        return returnList;
    }

    /** 
     * @Description：链表数据校验
     * @Author：juchengyang
     * @Create 2017-03-27
     */
    public static void checkList(List list) throws Exception {
        if (list.isEmpty()) {
            return;
        }
        Map<Object, Object> keyMap = new HashMap<>();
        Map<Object, Object> nextMap = new HashMap<>();
        Method methodGetId = list.get(0).getClass().getDeclaredMethod("getId");
        Method methodGetSortNum = list.get(0).getClass().getDeclaredMethod("getSortNum");
        for (int i = 0; i < list.size(); i++) {
            if (nextMap.containsKey(methodGetSortNum.invoke(list.get(i)))) {
                throw new BusinessException(ResultCode.FAILED, "数据出错：sorNum = "+methodGetSortNum.invoke(list.get(i))+"重复");
            }
            if (methodGetSortNum.invoke(list.get(i)).equals(methodGetId.invoke(list.get(i)))) {
                throw new BusinessException(ResultCode.FAILED, "数据出错："+methodGetId.invoke(list.get(i))+"指向自己");
            }
            keyMap.put(methodGetId.invoke(list.get(i)), methodGetSortNum.invoke(list.get(i)));
            nextMap.put(methodGetSortNum.invoke(list.get(i)), 0);
        }
        if (!nextMap.containsKey(0)) {
            throw new BusinessException(ResultCode.FAILED, "数据出错：不存在0（最后一位标识）");
        }
        for (int i = 0; i < list.size(); i++) {
            Integer next = Integer.parseInt(keyMap.get(methodGetId.invoke(list.get(i))).toString());
            if (next.equals(0)) {
                if (!nextMap.containsKey(methodGetId.invoke(list.get(i))) && nextMap.size() > 1) {
                    throw new BusinessException(ResultCode.FAILED, "没有指向最后一位的");
                }
                if (nextMap.get(next).equals(1)) {
                    throw new BusinessException(ResultCode.FAILED, "数据出错，最后一位不唯一");
                } else {
                    nextMap.put(next, 1);
                }

            } else {
                if (keyMap.containsKey(next)) {
                    if (nextMap.get(next).equals(1)) {
                        throw new BusinessException(ResultCode.FAILED, "数据出错，" + next + "重复");
                    } else {
                        nextMap.put(next, 1);
                    }
                } else {
                    throw new BusinessException(ResultCode.FAILED, next + " 没有对应的 id");
                }
            }
        }
    }
}
